home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / PPPFSM.C < prev    next >
C/C++ Source or Header  |  1997-01-19  |  19KB  |  861 lines

  1. /*
  2.  *  PPPFSM.C    -- PPP Finite State Machine
  3.  *
  4.  *    This implementation of PPP is declared to be in the public domain.
  5.  *
  6.  *    Jan 91    Bill_Simpson@um.cc.umich.edu
  7.  *        Computer Systems Consulting Services
  8.  *
  9.  *    Acknowledgements and correction history may be found in PPP.C
  10.  */
  11.  
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "iface.h"
  15. #include "ppp.h"
  16. #include "pppfsm.h"
  17. #include "ppplcp.h"
  18. #include "trace.h"
  19.  
  20. #if !defined(_lint)
  21. static char rcsid[] OPTIONAL = "$Id: pppfsm.c,v 1.10 1997/01/19 21:13:05 root Exp root $";
  22. #endif
  23.  
  24. #ifdef PPP
  25.  
  26. static const char *fsmStates[] =
  27. {
  28.     "Closed",
  29.     "Listen",
  30.     "Req Sent",
  31.     "Ack Rcvd",
  32.     "Ack Sent",
  33.     "Opened",
  34.     "TermSent"
  35. };
  36.  
  37. const char *fsmCodes[] =
  38. {
  39.     NULLCHAR,
  40.     "Config Req",
  41.     "Config Ack",
  42.     "Config Nak",
  43.     "Config Reject",
  44.     "Termin Req",
  45.     "Termin Ack",
  46.     "Code Reject",
  47.     "Protocol Reject",
  48.     "Echo Request",
  49.     "Echo Reply",
  50.     "Discard Request",
  51. };
  52.  
  53. static int fsm_sendtermreq (struct fsm_s * fsm_p);
  54. static int fsm_sendtermack (struct fsm_s * fsm_p, byte_t id);
  55. static void fsm_timeout (void *vp);
  56. static void fsm_reset (struct fsm_s * fsm_p);
  57. static void fsm_opening (struct fsm_s * fsm_p);
  58. static struct mbuf *htoncnf (struct config_hdr *cnf, struct mbuf *data);
  59.  
  60.  
  61.  
  62. /************************************************************************/
  63. /* Convert header in host form to network form */
  64.  
  65. static struct mbuf *
  66. htoncnf (struct config_hdr *cnf, struct mbuf *data)
  67. {
  68. struct mbuf *bp;
  69. register unsigned char *cp;
  70.  
  71.     /* Prepend bytes for LCP/IPCP header */
  72.     if ((bp = pushdown (data, CONFIG_HDR_LEN)) == NULLBUF) {
  73.         free_p (data);
  74.         return NULLBUF;
  75.     }
  76.     /* Load header with proper values */
  77.     cp = bp->data;
  78.     *cp++ = cnf->code;
  79.     *cp++ = cnf->id;
  80.     (void) put16 (cp, cnf->len);
  81.  
  82.     return bp;
  83. }
  84.  
  85.  
  86.  
  87. /* Extract header from incoming packet */
  88. int
  89. ntohcnf (struct config_hdr *cnf, struct mbuf **bpp)
  90. {
  91. unsigned char cnfb[CONFIG_HDR_LEN];
  92.  
  93.     if (cnf == NULL)
  94.         return -1;
  95.  
  96.     if (pullup (bpp, cnfb, CONFIG_HDR_LEN) < CONFIG_HDR_LEN)
  97.         return -1;
  98.  
  99.     cnf->code = cnfb[0];
  100.     cnf->id = cnfb[1];
  101.     cnf->len = get16 ((char *) &cnfb[2]);
  102.     return 0;
  103. }
  104.  
  105.  
  106.  
  107. /***************************************/
  108. /* Extract configuration option header */
  109.  
  110. int
  111. ntohopt (struct option_hdr *opt, struct mbuf **bpp)
  112. {
  113. unsigned char optb[OPTION_HDR_LEN];
  114.  
  115.     if (opt == NULL)
  116.         return -1;
  117.  
  118.     if (pullup (bpp, optb, OPTION_HDR_LEN) < OPTION_HDR_LEN)
  119.         return -1;
  120.  
  121.     opt->type = optb[0];
  122.     opt->len = optb[1];
  123.     return 0;
  124. }
  125.  
  126.  
  127.  
  128. /************************************************************************/
  129.  
  130. void
  131. fsm_no_action (struct fsm_s *fsm_p OPTIONAL)
  132. {
  133.     PPP_DEBUG_ROUTINES ("fsm_no_action()");
  134. }
  135.  
  136.  
  137.  
  138. int
  139. fsm_no_check (struct fsm_s *fsm_p OPTIONAL, struct config_hdr *hdr OPTIONAL, struct mbuf *bp OPTIONAL)
  140. {
  141.     PPP_DEBUG_ROUTINES ("fsm_no_check()");
  142.     return 0;
  143. }
  144.  
  145.  
  146.  
  147. /************************************************************************/
  148. /* General log routine */
  149.  
  150. void
  151. fsm_log (struct fsm_s *fsm_p, const char *comment)
  152. {
  153.     if (PPPtrace > 1)
  154.         trace_log (PPPiface, "%s PPP/%s %-8s; %s", fsm_p->ppp_p->iface->name,
  155.             fsm_p->pdc->name, fsmStates[fsm_p->state], comment);
  156. }
  157.  
  158.  
  159.  
  160. /************************************************************************/
  161. /* Set a timer in case an expected event does not occur */
  162.  
  163. void
  164. fsm_timer (struct fsm_s *fsm_p)
  165. {
  166.     PPP_DEBUG_ROUTINES ("fsm_timer()");
  167.  
  168.     start_timer (&(fsm_p->timer));
  169. }
  170.  
  171.  
  172.  
  173. /************************************************************************/
  174. /* Send a packet to the remote host */
  175.  
  176. int
  177. fsm_send (struct fsm_s *fsm_p, byte_t code, byte_t id, struct mbuf *data)
  178. {
  179. struct ppp_s *ppp_p = fsm_p->ppp_p;
  180. struct iface *iface = ppp_p->iface;
  181. struct config_hdr hdr;
  182. struct mbuf *bp;
  183.  
  184.     switch (hdr.code = code) {
  185.         case CONFIG_REQ:
  186.         case TERM_REQ:
  187.         case ECHO_REQ:
  188.             /* Save ID field for match against replies from remote host */
  189.             fsm_p->lastid = ppp_p->id;
  190.             /* fallthru */
  191.         case PROT_REJ:
  192.         case DISCARD_REQ:
  193.             /* Use a unique ID field value */
  194.             hdr.id = ppp_p->id++;
  195.             break;
  196.  
  197.         case CONFIG_ACK:
  198.         case CONFIG_NAK:
  199.         case CONFIG_REJ:
  200.         case TERM_ACK:
  201.         case CODE_REJ:
  202.         case ECHO_REPLY:
  203.             /* Use ID sent by remote host */
  204.             hdr.id = id;
  205.             break;
  206.  
  207.         default:
  208.             /* we're in trouble */
  209.             trace_log (PPPiface, "%s PPP/%s %-8s; Send with bogus code: %d",
  210.                 iface->name, fsm_p->pdc->name, fsmStates[fsm_p->state], code);
  211.             return -1;
  212.     }
  213.  
  214.     switch (code) {
  215.         case ECHO_REQ:
  216.         case ECHO_REPLY:
  217.         case DISCARD_REQ:
  218.             {
  219.                 struct lcp_s *lcp_p = fsm_p->pdv;
  220.  
  221.                 if ((bp = pushdown (data, 4)) == NULLBUF) {
  222.                     free_p (data);
  223.                     return -1;
  224.                 }
  225.                 (void) put32 (bp->data, lcp_p->local.work.magic_number);
  226.                 data = bp;
  227.             }
  228.             break;
  229.         default:
  230.             break;
  231.     }
  232.  
  233.     hdr.len = len_p (data) + CONFIG_HDR_LEN;
  234.  
  235.     /* Prepend header to packet data */
  236.     if ((data = htoncnf (&hdr, data)) == NULLBUF)
  237.         return -1;
  238.  
  239.     if (PPPtrace > 1)
  240.         trace_log (PPPiface, "%s PPP/%s %-8s; Sending %s, id: %d, len: %d",
  241.             iface->name, fsm_p->pdc->name, fsmStates[fsm_p->state],
  242.             fsmCodes[code], hdr.id, hdr.len);
  243.  
  244.     ppp_p->OutNCP[fsm_p->pdc->fsmi]++;
  245.  
  246.     return ((*iface->output) (iface, NULLCHAR, NULLCHAR, fsm_p->pdc->protocol, data));
  247. }
  248.  
  249.  
  250.  
  251. /************************************************************************/
  252. /* Send a configuration request */
  253.  
  254. int
  255. fsm_sendreq (struct fsm_s *fsm_p)
  256. {
  257. struct mbuf *bp;
  258.  
  259.     PPP_DEBUG_ROUTINES ("fsm_sendreq()");
  260.  
  261. #if 0
  262.     if (fsm_p->retry <= 0)
  263.         return -1;
  264. #endif
  265.  
  266.     fsm_p->retry--;
  267.     fsm_timer (fsm_p);
  268.  
  269.     bp = (*fsm_p->pdc->makereq) (fsm_p);
  270.     return (fsm_send (fsm_p, CONFIG_REQ, 0, bp));
  271. }
  272.  
  273.  
  274.  
  275. /************************************************************************/
  276. /* Send a termination request */
  277.  
  278. static int
  279. fsm_sendtermreq (struct fsm_s *fsm_p)
  280. {
  281.     PPP_DEBUG_ROUTINES ("fsm_sendtermreq()");
  282.  
  283. #if 0
  284.     if (fsm_p->retry <= 0)
  285.         return -1;
  286. #endif
  287.  
  288.     fsm_p->retry--;
  289.     fsm_timer (fsm_p);
  290.     return (fsm_send (fsm_p, TERM_REQ, 0, NULLBUF));
  291. }
  292.  
  293.  
  294.  
  295. /************************************************************************/
  296. /* Send Terminate Ack */
  297.  
  298. static int
  299. fsm_sendtermack (struct fsm_s *fsm_p, byte_t id)
  300. {
  301.     PPP_DEBUG_ROUTINES ("fsm_sendtermack()");
  302.  
  303.     return (fsm_send (fsm_p, TERM_ACK, id, NULLBUF));
  304. }
  305.  
  306.  
  307.  
  308. /************************************************************************/
  309. /* Reset state machine */
  310.  
  311. static void
  312. fsm_reset (struct fsm_s *fsm_p)
  313. {
  314.     PPP_DEBUG_ROUTINES ("fsm_reset()");
  315.  
  316.     fsm_p->state = (fsm_p->flags & (FSM_ACTIVE | FSM_PASSIVE))
  317.         ? fsmLISTEN : fsmCLOSED;
  318.     fsm_p->retry = fsm_p->try_req;
  319.     fsm_p->retry_nak = fsm_p->try_nak;
  320.  
  321.     (*fsm_p->pdc->reset) (fsm_p);
  322. }
  323.  
  324.  
  325.  
  326. /************************************************************************/
  327. /* Configuration negotiation complete */
  328.  
  329. static void
  330. fsm_opening (struct fsm_s *fsm_p)
  331. {
  332.     fsm_log (fsm_p, "Opened");
  333.  
  334.     stop_timer (&(fsm_p->timer));
  335.  
  336.     (*fsm_p->pdc->opening) (fsm_p);
  337.     fsm_p->state = fsmOPENED;
  338. }
  339.  
  340.  
  341.  
  342. /************************************************************************/
  343. /*            E V E N T   P R O C E S S I N G            */
  344. /************************************************************************/
  345.  
  346. /* Process incoming packet */
  347.  
  348. void
  349. fsm_proc (struct fsm_s *fsm_p, struct mbuf *bp)
  350. {
  351. struct config_hdr hdr;
  352.  
  353.     PPPtrace = fsm_p->ppp_p->trace;
  354.     PPPiface = fsm_p->ppp_p->iface;
  355.  
  356.     if (ntohcnf (&hdr, &bp) == -1)
  357.         fsm_log (fsm_p, "short configuration packet");
  358.  
  359.     if (PPPtrace > 1)
  360.         trace_log (PPPiface, "%s PPP/%s %-8s; Processing %s, id: %d, len: %d",
  361.             fsm_p->ppp_p->iface->name, fsm_p->pdc->name, fsmStates[fsm_p->state],
  362.             fsmCodes[hdr.code], hdr.id, hdr.len);
  363.  
  364.     hdr.len -= CONFIG_HDR_LEN;    /* Length includes envelope */
  365.     trim_mbuf (&bp, hdr.len);    /* Trim off padding */
  366.  
  367.     switch (hdr.code) {
  368.         case CONFIG_REQ:
  369.             switch (fsm_p->state) {
  370.                 case fsmOPENED:    /* Unexpected event? */
  371.                     (*fsm_p->pdc->closing) (fsm_p);
  372.                     fsm_reset (fsm_p);
  373.                     /* fallthru */
  374.                 case fsmLISTEN:
  375.                     (*fsm_p->pdc->starting) (fsm_p);
  376.                     (void) fsm_sendreq (fsm_p);
  377.                     /* fallthru */
  378.                 case fsmREQ_Sent:
  379.                 case fsmACK_Sent:    /* Unexpected event? */
  380.                     fsm_p->state =
  381.                         ((*fsm_p->pdc->request) (fsm_p, &hdr, bp) == 0)
  382.                         ? fsmACK_Sent : fsmREQ_Sent;
  383.                     break;
  384.  
  385.                 case fsmACK_Rcvd:
  386.                     if ((*fsm_p->pdc->request) (fsm_p, &hdr, bp) == 0)
  387.                         fsm_opening (fsm_p);
  388.                     else     /* give peer time to respond */
  389.                         fsm_timer (fsm_p);
  390.                     break;
  391.  
  392.                 case fsmCLOSED:
  393.                     /* Don't accept any connections */
  394.                     (void) fsm_sendtermack (fsm_p, hdr.id);
  395.                     /* fallthru */
  396.                 case fsmTERM_Sent:
  397.                     /* We are attempting to close connection; */
  398.                     /* wait for timeout to resend a Terminate Request */
  399.                     free_p (bp);
  400.                     break;
  401.                 default:
  402.                     break;
  403.             }
  404.             break;
  405.  
  406.         case CONFIG_ACK:
  407.             switch (fsm_p->state) {
  408.                 case fsmREQ_Sent:
  409.                     if ((*fsm_p->pdc->ack) (fsm_p, &hdr, bp) == 0)
  410.                         fsm_p->state = fsmACK_Rcvd;
  411.                     break;
  412.  
  413.                 case fsmACK_Sent:
  414.                     if ((*fsm_p->pdc->ack) (fsm_p, &hdr, bp) == 0)
  415.                         fsm_opening (fsm_p);
  416.                     break;
  417.  
  418.                 case fsmOPENED:    /* Unexpected event? */
  419.                     (*fsm_p->pdc->closing) (fsm_p);
  420.                     (*fsm_p->pdc->starting) (fsm_p);
  421.                     fsm_reset (fsm_p);
  422.                     /* fallthru */
  423.                 case fsmACK_Rcvd:    /* Unexpected event? */
  424.                     free_p (bp);
  425.                     (void) fsm_sendreq (fsm_p);
  426.                     fsm_p->state = fsmREQ_Sent;
  427.                     break;
  428.  
  429.                 case fsmCLOSED:
  430.                 case fsmLISTEN:
  431.                     /* Out of Sync; kill the remote */
  432.                     (void) fsm_sendtermack (fsm_p, hdr.id);
  433.                     /* fallthru */
  434.                 case fsmTERM_Sent:
  435.                     /* We are attempting to close connection; */
  436.                     /* wait for timeout to resend a Terminate Request */
  437.                     free_p (bp);
  438.                     break;
  439.                 default:
  440.                     break;
  441.             }
  442.             break;
  443.  
  444.         case CONFIG_NAK:
  445.             switch (fsm_p->state) {
  446.                 case fsmREQ_Sent:
  447.                 case fsmACK_Sent:
  448.                     /* Update our config request to reflect NAKed options */
  449.                     if ((*fsm_p->pdc->nak) (fsm_p, &hdr, bp) == 0)
  450.                         /* Send updated config request */
  451.                         (void) fsm_sendreq (fsm_p);
  452.                     break;
  453.  
  454.                 case fsmOPENED:    /* Unexpected event? */
  455.                     (*fsm_p->pdc->closing) (fsm_p);
  456.                     (*fsm_p->pdc->starting) (fsm_p);
  457.                     fsm_reset (fsm_p);
  458.                     /* fallthru */
  459.                 case fsmACK_Rcvd:    /* Unexpected event? */
  460.                     free_p (bp);
  461.                     (void) fsm_sendreq (fsm_p);
  462.                     fsm_p->state = fsmREQ_Sent;
  463.                     break;
  464.  
  465.                 case fsmCLOSED:
  466.                 case fsmLISTEN:
  467.                     /* Out of Sync; kill the remote */
  468.                     (void) fsm_sendtermack (fsm_p, hdr.id);
  469.                     /* fallthru */
  470.                 case fsmTERM_Sent:
  471.                     /* We are attempting to close connection; */
  472.                     /* wait for timeout to resend a Terminate Request */
  473.                     free_p (bp);
  474.                     break;
  475.                 default:
  476.                     break;
  477.             }
  478.             break;
  479.  
  480.         case CONFIG_REJ:
  481.             switch (fsm_p->state) {
  482.                 case fsmREQ_Sent:
  483.                 case fsmACK_Sent:
  484.                     if ((*fsm_p->pdc->reject) (fsm_p, &hdr, bp) == 0)
  485.                         (void) fsm_sendreq (fsm_p);
  486.                     break;
  487.  
  488.                 case fsmOPENED:    /* Unexpected event? */
  489.                     (*fsm_p->pdc->closing) (fsm_p);
  490.                     (*fsm_p->pdc->starting) (fsm_p);
  491.                     fsm_reset (fsm_p);
  492.                     /* fallthru */
  493.                 case fsmACK_Rcvd:    /* Unexpected event? */
  494.                     free_p (bp);
  495.                     (void) fsm_sendreq (fsm_p);
  496.                     fsm_p->state = fsmREQ_Sent;
  497.                     break;
  498.  
  499.                 case fsmCLOSED:
  500.                 case fsmLISTEN:
  501.                     /* Out of Sync; kill the remote */
  502.                     (void) fsm_sendtermack (fsm_p, hdr.id);
  503.                     /* fallthru */
  504.                 case fsmTERM_Sent:
  505.                     /* We are attempting to close connection; */
  506.                     /* wait for timeout to resend a Terminate Request */
  507.                     free_p (bp);
  508.                     break;
  509.                 default:
  510.                     break;
  511.             }
  512.             break;
  513.  
  514.         case TERM_REQ:
  515.             fsm_log (fsm_p, "Peer requested Termination");
  516.  
  517.             switch (fsm_p->state) {
  518.                 case fsmOPENED:
  519.                     (void) fsm_sendtermack (fsm_p, hdr.id);
  520.                     (*fsm_p->pdc->closing) (fsm_p);
  521.                     (*fsm_p->pdc->stopping) (fsm_p);
  522.                     fsm_reset (fsm_p);
  523.                     break;
  524.  
  525.                 case fsmACK_Rcvd:
  526.                 case fsmACK_Sent:
  527.                     fsm_p->state = fsmREQ_Sent;
  528.                     /* fallthru */
  529.                 case fsmREQ_Sent:
  530.                 case fsmTERM_Sent:
  531.                     /* waiting for timeout */
  532.                     /* fallthru */
  533.                 case fsmCLOSED:
  534.                 case fsmLISTEN:
  535.                     /* Unexpected, but make them happy */
  536.                     (void) fsm_sendtermack (fsm_p, hdr.id);
  537.                     break;
  538.                 default:
  539.                     break;
  540.             }
  541.             break;
  542.  
  543.         case TERM_ACK:
  544.             switch (fsm_p->state) {
  545.                 case fsmTERM_Sent:
  546.                     stop_timer (&(fsm_p->timer));
  547.  
  548.                     fsm_log (fsm_p, "Terminated");
  549.                     (*fsm_p->pdc->stopping) (fsm_p);
  550.                     fsm_reset (fsm_p);
  551.                     break;
  552.  
  553.                 case fsmOPENED:
  554.                     /* Remote host has abruptly closed connection */
  555.                     fsm_log (fsm_p, "Terminated unexpectly");
  556.                     (*fsm_p->pdc->closing) (fsm_p);
  557.                     fsm_reset (fsm_p);
  558.                     if (fsm_sendreq (fsm_p) == 0)
  559.                         fsm_p->state = fsmREQ_Sent;
  560.                     break;
  561.  
  562.                 case fsmACK_Sent:
  563.                 case fsmACK_Rcvd:
  564.                     fsm_p->state = fsmREQ_Sent;
  565.                     /* fallthru */
  566.                 case fsmREQ_Sent:
  567.                     /* waiting for timeout */
  568.                     /* fallthru */
  569.                 case fsmCLOSED:
  570.                 case fsmLISTEN:
  571.                 default:
  572.                     /* Unexpected, but no action needed */
  573.                     break;
  574.             }
  575.             break;
  576.  
  577.         case CODE_REJ:
  578.             trace_log (PPPiface, "%s PPP/%s Code Reject; indicates faulty implementation",
  579.                 fsm_p->ppp_p->iface->name, fsm_p->pdc->name);
  580.             (*fsm_p->pdc->stopping) (fsm_p);
  581.             fsm_reset (fsm_p);
  582.             free_p (bp);
  583.             break;
  584.  
  585.         case PROT_REJ:
  586.             trace_log (PPPiface, "%s PPP/%s Protocol Reject; please do not use this protocol",
  587.                 fsm_p->ppp_p->iface->name, fsm_p->pdc->name);
  588.             free_p (bp);
  589.             break;
  590.  
  591.         case ECHO_REQ:
  592.             switch (fsm_p->state) {
  593.                 case fsmOPENED:
  594.                     (void) fsm_send (fsm_p, ECHO_REPLY, hdr.id, bp);
  595.                     break;
  596.  
  597.                 case fsmCLOSED:
  598.                 case fsmLISTEN:
  599.                     /* Out of Sync; kill the remote */
  600.                     (void) fsm_sendtermack (fsm_p, hdr.id);
  601.                     /* fallthru */
  602.                 case fsmREQ_Sent:
  603.                 case fsmACK_Rcvd:
  604.                 case fsmACK_Sent:
  605.                 case fsmTERM_Sent:
  606.                 default:
  607.                     /* ignore */
  608.                     free_p (bp);
  609.                     break;
  610.             }
  611.             break;
  612.  
  613.         case ECHO_REPLY:
  614.         case DISCARD_REQ:
  615.         case QUALITY_REPORT:
  616.             free_p (bp);
  617.             break;
  618.  
  619.         default:
  620.             trace_log (PPPiface, "%s PPP/%s Unknown packet type: %d; Sending Code Reject",
  621.                 fsm_p->ppp_p->iface->name, fsm_p->pdc->name, hdr.code);
  622.  
  623.             hdr.len += CONFIG_HDR_LEN;    /* restore length */
  624.             bp = htoncnf (&hdr, bp);    /* put header back on */
  625.             (void) fsm_send (fsm_p, CODE_REJ, hdr.id, bp);
  626.  
  627.             switch (fsm_p->state) {
  628.                 case fsmREQ_Sent:
  629.                 case fsmACK_Rcvd:
  630.                 case fsmACK_Sent:
  631.                 case fsmOPENED:
  632.                     fsm_p->state = fsmLISTEN;
  633.                     break;
  634.  
  635.                 case fsmCLOSED:
  636.                 case fsmLISTEN:
  637.                 case fsmTERM_Sent:
  638.                 default:
  639.                     /* no change */
  640.                     break;
  641.             }
  642.             break;
  643.     }
  644. }
  645.  
  646.  
  647.  
  648. /************************************************************************/
  649. /* Timeout while waiting for reply from remote host */
  650.  
  651. static void
  652. fsm_timeout (void *vp)
  653. {
  654. struct fsm_s *fsm_p = (struct fsm_s *) vp;
  655.  
  656.     PPPtrace = fsm_p->ppp_p->trace;
  657.     PPPiface = fsm_p->ppp_p->iface;
  658.  
  659.     fsm_log (fsm_p, "Timeout");
  660.  
  661.     switch (fsm_p->state) {
  662.         case fsmREQ_Sent:
  663.         case fsmACK_Rcvd:
  664.         case fsmACK_Sent:
  665.             if (fsm_p->retry > 0) {
  666.                 (void) fsm_sendreq (fsm_p);
  667.                 if (fsm_p->state == fsmACK_Rcvd)
  668.                     fsm_p->state = fsmREQ_Sent;
  669.             } else {
  670.                 fsm_log (fsm_p, "Request retry exceeded");
  671.                 fsm_reset (fsm_p);
  672.             }
  673.             break;
  674.  
  675.         case fsmTERM_Sent:
  676.             if (fsm_p->retry > 0)
  677.                 (void) fsm_sendtermreq (fsm_p);
  678.             else {
  679.                 fsm_log (fsm_p, "Terminate retry exceeded");
  680.                 (*fsm_p->pdc->stopping) (fsm_p);
  681.                 fsm_reset (fsm_p);
  682.             }
  683.             break;
  684.  
  685.         case fsmCLOSED:
  686.         case fsmLISTEN:
  687.         case fsmOPENED:
  688.         default:
  689.             /* nothing to do */
  690.             break;
  691.     }
  692. }
  693.  
  694.  
  695.  
  696. /************************************************************************/
  697. /*            I N I T I A L I Z A T I O N            */
  698. /************************************************************************/
  699.  
  700. /* Start FSM (after open event, and physical line up) */
  701.  
  702. void
  703. fsm_start (struct fsm_s *fsm_p)
  704. {
  705.     if (fsm_p->pdv == NULL)
  706.         return;
  707.  
  708.     PPPtrace = fsm_p->ppp_p->trace;
  709.     PPPiface = fsm_p->ppp_p->iface;
  710.  
  711.     fsm_log (fsm_p, "Start");
  712.  
  713.     if (!(fsm_p->flags & (FSM_ACTIVE | FSM_PASSIVE)))
  714.         return;
  715.  
  716.     switch (fsm_p->state) {
  717.         case fsmCLOSED:
  718.         case fsmLISTEN:
  719.         case fsmTERM_Sent:
  720.             (*fsm_p->pdc->starting) (fsm_p);
  721.             fsm_reset (fsm_p);
  722.  
  723.             if (fsm_p->flags & FSM_ACTIVE) {
  724.                 (void) fsm_sendreq (fsm_p);
  725.                 fsm_p->state = fsmREQ_Sent;
  726.             }
  727.             break;
  728.         default:
  729.             /* already started */
  730.             break;
  731.     }
  732. }
  733.  
  734.  
  735.  
  736. /************************************************************************/
  737. /* Physical Line Down Event */
  738.  
  739. void
  740. fsm_down (struct fsm_s *fsm_p)
  741. {
  742.     if (fsm_p->pdv == NULL)
  743.         return;
  744.  
  745.     PPPtrace = fsm_p->ppp_p->trace;
  746.     PPPiface = fsm_p->ppp_p->iface;
  747.  
  748.     fsm_log (fsm_p, "Down");
  749.  
  750.     switch (fsm_p->state) {
  751.         case fsmREQ_Sent:
  752.         case fsmACK_Rcvd:
  753.         case fsmACK_Sent:
  754.             stop_timer (&(fsm_p->timer));
  755.             fsm_reset (fsm_p);
  756.             break;
  757.  
  758.         case fsmOPENED:
  759.             (*fsm_p->pdc->closing) (fsm_p);
  760.             /* fallthru */
  761.         case fsmTERM_Sent:
  762.             fsm_reset (fsm_p);
  763.             break;
  764.  
  765.         case fsmCLOSED:
  766.         case fsmLISTEN:
  767.         default:
  768.             /* nothing to do */
  769.             break;
  770.     }
  771. }
  772.  
  773.  
  774.  
  775. /************************************************************************/
  776. /* Close the connection */
  777.  
  778. void
  779. fsm_close (struct fsm_s *fsm_p)
  780. {
  781.     if (fsm_p->pdv == NULL)
  782.         return;
  783.  
  784.     PPPtrace = fsm_p->ppp_p->trace;
  785.     PPPiface = fsm_p->ppp_p->iface;
  786.  
  787.     fsm_log (fsm_p, "Close");
  788.  
  789.     switch (fsm_p->state) {
  790.         case fsmOPENED:
  791.             (*fsm_p->pdc->closing) (fsm_p);
  792.             /* fallthru */
  793.         case fsmACK_Sent:
  794.             fsm_p->retry = fsm_p->try_terminate;
  795.             (void) fsm_sendtermreq (fsm_p);
  796.             fsm_p->state = fsmTERM_Sent;
  797.             break;
  798.  
  799.         case fsmREQ_Sent:
  800.         case fsmACK_Rcvd:
  801.             /* simply wait for REQ timeout to expire */
  802.             fsm_p->retry = 0;
  803.             fsm_p->state = fsmTERM_Sent;
  804.             break;
  805.  
  806.         case fsmLISTEN:
  807.             fsm_p->state = fsmCLOSED;
  808.             break;
  809.  
  810.         case fsmTERM_Sent:
  811.         case fsmCLOSED:
  812.         default:
  813.             /* nothing to do */
  814.             break;
  815.     }
  816. }
  817.  
  818.  
  819.  
  820. /************************************************************************/
  821. /* Initialize the fsm for this protocol
  822.  * Called from protocol _init
  823.  */
  824.  
  825. void
  826. fsm_init (struct fsm_s *fsm_p)
  827. {
  828. struct timer *t = &(fsm_p->timer);
  829.  
  830.     PPP_DEBUG_ROUTINES ("fsm_init()");
  831.  
  832.     fsm_p->try_req = fsm_p->pdc->try_req;
  833.     fsm_p->try_nak = fsm_p->pdc->try_nak;
  834.     fsm_p->try_terminate = fsm_p->pdc->try_terminate;
  835.     fsm_reset (fsm_p);
  836.  
  837.     /* Initialize timer */
  838.     t->func = (void (*)(void *)) fsm_timeout;
  839.     t->arg = (void *) fsm_p;
  840.     set_timer (t, fsm_p->pdc->timeout);
  841.     fsm_timer (fsm_p);
  842.     stop_timer (t);
  843. }
  844.  
  845.  
  846.  
  847. void
  848. fsm_free (struct fsm_s *fsm_p)
  849. {
  850.     if (fsm_p->pdv != NULL) {
  851.         (*fsm_p->pdc->free) (fsm_p);
  852.  
  853.         free (fsm_p->pdv);
  854.         fsm_p->pdv = NULL;
  855.     }
  856. }
  857.  
  858.  
  859.  
  860. #endif /* PPP */
  861.